/** 可识别联合类型*/
//就是利用联合类型中的共有字段进行类型保护的一种技巧,相同字段的不同取值作为可辨识的依据
/*
你可以合并单例类型，联合类型，类型保护和类型别名来创建一个叫做 可辨识联合的高级模式，它也称做 标签联合或 代数数据类型。 可辨识联合在函数式编程很有用处。 一些语言会自动地为你辨识联合；而TypeScript则基于已有的JavaScript模式。 它具有3个要素：
  + 具有普通的单例类型属性— 可辨识的特征。
  + 一个类型别名包含了那些类型的联合— 联合。
  + 利用公有属性进行Type guard。

You can combine singleton types, union types, type guards, and type aliases to build an advanced pattern called discriminated unions, also known as tagged unions or algebraic data types. Discriminated unions are useful in functional programming. Some languages automatically discriminate unions for you; TypeScript instead builds on JavaScript patterns as they exist today. There are three ingredients:

1. Types that have a common, singleton type property — the discriminant.
2. A type alias that takes the union of those types — the union.
3. Type guards on the common property.


需要至少有一个公有字段
共有字段是可穷举的
*/

type Props = {
  action: 'create'; //← 1. 可辨识的特征 或 标签(the discriminant or tag)
  name: string;
} | {
  action: 'update';
  name: string;
  id: number;
};

function fn(a: Props) {
  if(a.action === 'create'){
    console.log(a.name);
    /*
      (parameter) a: {
        action: "create";
        name: string;
      }
    */
  }else{
    /*
      (parameter) a: {
        action: "update";
        name: string;
        id: number;
      }
    */
    console.log(a.id)
  }
}


//---
/** 共有字段是可穷举的*/
/*

*/
type Props2 = {
  action: number;
  name: string;
} | {
  action: string;
  name: string;
  id: number;
};

function fn2(a: Props) {
  if(typeof a.action === 'number'){
    console.log(a.name);
  }else{
    console.log(a.id) // 依然报错
  }
}

//---

/** 多用于redux的action*/
type Action = {
  type:string;
  payload: any;
}

type Action2 = {
  type:'ADD';
  payload: number
}|{
  type:'ADD_STRING';
  payload: string
}|{
  type:'ADD_DATE';
  payload:Date
}

function reducer(state:any, action:Action2) {
  switch (action.type) {
    case 'ADD':
      action.payload; //(property) payload: number
      break;
    case 'ADD_STRING':
      action.payload // (property) payload: string
  }
}
